feat: add merge() method + basedpyright type checking#41
Merged
Conversation
Op.merge_into flattens nested dicts to the wrong indentation level when
creating intermediate keys (e.g. upsert('parent', 'child', value={'x': 1})).
Fix by using add(key, None) + replace(value) which correctly serializes
the full nested structure.
Adds a regression test that fails without the fix.
Add test classes for list replacement, type promotion, path creation, and no-op merge scenarios. Fix _create_at to correctly handle nested dict values by using placeholder+replace instead of direct Op.add which flattens nested structures.
- Short-circuit list diffing in merge (replace entirely per spec) - Add root-exists comment to merge() for consistency with sync() - Add flow sequence tests to test_merge.py
3c01dc9 to
61083af
Compare
# Conflicts: # src/yamltrip/document.py # tests/test_document.py
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an additive deep-merge capability to yamltrip by introducing merge() on Document (immutable) and Editor (mutable), implemented via existing patch-diff machinery with a new remove_extra toggle to prevent key deletions during mapping diffs.
Changes:
- Introduces
Document.merge()andEditor.merge()to perform recursive additive merges (never deletes mapping keys; lists replace entirely). - Extends
src/yamltrip/sync.pydiff engine withremove_extrato support “sync” vs “merge” semantics using the same patch computation. - Adds merge-focused tests plus a design/semantics spec document.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_merge.py |
Adds unit tests covering mapping merge, list replacement, type promotion, missing-path creation, no-op behavior, and Editor integration. |
src/yamltrip/sync.py |
Adds remove_extra flag to mapping/list diff logic to enable additive merge behavior without deleting extra keys. |
src/yamltrip/editor.py |
Adds Editor.merge() delegating to Document.merge(). |
src/yamltrip/document.py |
Adds Document.merge() implementation using _compute_patches(..., remove_extra=False) plus flow-sequence handling similar to sync(). |
doc/specs/2026-05-22-deep-merge-design.md |
Documents merge semantics, API, and testing plan (needs minor corrections per review comments). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ode, rewrite docstring, introduce DiffMode enum
- Add basedpyright as dev dependency - Add typing_extensions as runtime dependency (for @OverRide on py3.10/3.11) - Configure [tool.basedpyright] with appropriate suppressions - Add basedpyright hook to .pre-commit-config.yaml (runs in CI via prek) - Switch to relative imports to break import cycles - Remove redundant Component.key()/Component.index() static factories - Retype _create_at child_keys as tuple[str, ...] with _ensure_str_keys - Make normalize_keys and compute_patches public (with tests) - Add @OverRide decorators and type annotations for class attributes - Enable reportUnusedCallResult, reportUnknownMemberType, reportUnnecessaryIsInstance, reportImplicitStringConcatenation
merge() method for additive deep mergeCo-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
merge()method toDocumentandEditorthat recursively merges a value into an existing mapping without removing extra keys, and addsbasedpyrightstatic type checking to the project.Deep Merge
Complements
sync()which enforces exact structure (removing keys not in the target).merge()is additive — it updates matching keys, adds new keys, and never deletes.Semantics
Example
Basedpyright Type Checking
basedpyrightas dev dependency with strict-ish config in[tool.basedpyright]typing_extensionsas runtime dependency (for@overrideon Python 3.10/3.11)prek)Component.key()/Component.index()static factory methods_create_atto accepttuple[str, ...]with_ensure_str_keys()boundarynormalize_keysandcompute_patchespublic (with tests)@overridedecorators and explicit type annotationsBreaking Changes
Component.key(name)/Component.index(idx)removed — UseComponent.Key(name)/Component.Index(idx)constructors instead. The static factory methods were redundant wrappers around the enum variant constructors and caused type-checking conflicts. This is acceptable under pre-1.0 semver (current version: 0.5.0).Changes
Merge
src/yamltrip/sync.py—compute_patchesgainsremove_extrakeyword (defaultTrue) +DiffModeenumsrc/yamltrip/document.py—Document.merge()method + fix for_create_atnested dict flattening bugsrc/yamltrip/editor.py—Editor.merge()delegatetests/test_merge.py— 12 tests covering core merge, edge cases, and Editor integrationType Checking
pyproject.toml— basedpyright config + typing_extensions dependency.pre-commit-config.yaml— basedpyright hooksrc/yamltrip/_core.pyi—@overridedecorators, removed static factoriessrc/yamltrip/document.py— relative imports, type annotations,@overridesrc/yamltrip/editor.py— relative imports, type annotations,@overridesrc/yamltrip/sync.py— relative importssrc/types.rs— removed static factory methods, updated__repr__tests/test_normalize_keys.py— 8 tests fornormalize_keystests/test_compute_patches.py— 10 tests forcompute_patches.importlinter— removed stale ignore rules (no longer needed with relative imports)